package waal.pc.process;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import waal.pc.backend.Log;
import waal.pc.frontend.ProcessTab;

public class XMLProcess extends Thread {

	private ProcessTab tab;
	private File inFile;
	private Document xmlDocument;
	private Element root;
	private Map<String, Double> multiMap = new HashMap<String, Double>();
	
	public XMLProcess(ProcessTab tab, File inFile) {
		this.tab = tab;
		this.inFile = inFile;
		this.multiMap.put("us", 1.0);
		this.multiMap.put("ms", 1e3);
		this.multiMap.put("s", 1e6);
		this.multiMap.put("min", 60e6);
		this.multiMap.put("h", 3.6e9);
		
		this.start();
	}
	
	
	@SuppressWarnings("unchecked")
	public void run() {
		Element elm, elm2;
		String str1, str2, comment;
		long timebase;
		List<Element> steps;
		int time;
		try {
			this.xmlDocument = new SAXBuilder(true).build(this.inFile);
			
			/** Bestimmung des Wurzel-Knotens */
			this.root = this.xmlDocument.getRootElement();
			elm = this.root.getChild("description");
			this.tab.setDescription(elm.getChildTextTrim("name"), elm.getChildTextTrim("coment"));
			elm = this.root.getChild("timebase");
			str1 = elm.getAttributeValue("unit");
			str2 = elm.getTextTrim();
			timebase = (long) (this.getInt(str2) * this.multiMap.get(str1)); 
			this.tab.setTimebase(timebase, str2, str1);
			elm = this.root.getChild("controls");
			if(elm != null) {
				@SuppressWarnings("unused")
				List<Element> controls = elm.getChildren("control");
				
			}
			
			elm = this.root.getChild("steps");
			steps = elm.getChildren();
			for(Iterator<Element> is = steps.iterator(); is.hasNext(); ) {
				elm = is.next();
				time = this.getInt(elm.getChildTextTrim("time"));
				comment = elm.getChildText("comment");
				if((elm2 = elm.getChild("digital")) != null  ) {
					this.moduleStep(time, 1, elm2, comment);
				} else if((elm2 = elm.getChild("analog")) != null  ) {
					this.moduleStep(time, 0, elm2, comment);
				} else if((elm2 = elm.getChild("virtual")) != null  ) {
					this.moduleStep(time, 2, elm2, comment);
				} else if((elm2 = elm.getChild("config")) != null  ) {
					this.configStep(time, elm2, comment);
				} else {
					Log.addToErrorLog("invalid step");
				}
			}
			this.tab.xmlProcessEnd();
			
		 } catch (JDOMException | IOException e) {
			//TODO
			 Log.addToErrorLog("Fehler");
			 e.printStackTrace();
		 }	
	}
	
	private void configStep(int time, Element elm, String comment) {
		Log.addToDebug(2, "XMLProcess", "moduleStep", "Make config step for time: " + time);
		int command = this.getInt(elm.getChildText("command"));
		
		@SuppressWarnings("unchecked")
		List<Element> para = elm.getChildren("parameter");
		if(!para.isEmpty()) {
			int i = 0;
			int[] parameters = new int[para.size()];
			for(Iterator<Element> ip = para.iterator(); ip.hasNext();  ) {
				parameters[i++] = this.getInt(ip.next().getTextTrim());
			}
			this.tab.addConfigLine(time, command, comment, parameters);
		} else {
			this.tab.addConfigLine(time, command, comment);
		}
	}
	
	private void moduleStep(int time, int type, Element elm, String comment) {
		Log.addToDebug(2, "XMLProcess", "moduleStep", "Make module step for time: " + time + "module type: " + type );
		int module, channel, command;
		
		module = this.getInt(elm.getChildText("module"));
		channel = this.getInt(elm.getChildText("channel"));
		command = this.getInt(elm.getChildText("command"));
		@SuppressWarnings("unchecked")
		List<Element> para = elm.getChildren("parameter");
		if(!para.isEmpty()) {
			int i = 0;
			int[] parameters = new int[para.size()];
			for(Iterator<Element> ip = para.iterator(); ip.hasNext();  ) {
				parameters[i++] = this.getInt(ip.next().getTextTrim());
			}
			this.tab.addModuelLine(time, module, channel, command, type, comment, parameters);
		} else {
			this.tab.addModuelLine(time, module, channel, command, type,comment);
		}
	}
	
	private int getInt(String value) {
		int i;
		if(value.length() < 3) {
			i= this.getDecInt(value);
		} else {
			if(value.toLowerCase().charAt(1) == 'x') {
				i =  this.getHexInt(value);
			} else {
				i = this.getDecInt(value);
			}
		}
		//Log.addToDebug(2, "XMLProcess", "getInt", "out value: " + i );
		return i;
	}
	
	private int getHexInt(String value) {
		int i;
		//Log.addToDebug(2, "XMLProcess", "getHexInt", "value is hex: " + value);
		try {
			i =  Integer.parseInt(value.substring(2), 16);
		} catch(NumberFormatException e) {
			Log.addToErrorLog("XMLProcess - getHexInt - Fehler" );
			i = -1;
		}
		return i;
	}

	private int getDecInt(String value) {
		int i;
		//Log.addToDebug(2, "XMLProcess", "getDecInt", "value is dec: " + value);
		try {
			i = Integer.parseInt(value);
		} catch(NumberFormatException e) {
			Log.addToErrorLog("XMLProcess - getDecInt - Fehler" );
			i = -1;
		} 
		return i;
	}
}
